#include "hanpin_index_query.h"

HanpinIndex::HanpinIndex()
    : IndexTableBase()
{ }

HanpinIndex::~HanpinIndex()
{ }

int HanpinIndex::InitServer(
    const SDTCHost& dtchost,
    const std::string& bindAddr)
{
    std::string _MasterAddress = "127.0.0.1";
    std::stringstream ss;
    uint32_t port = 0;
    if (dtchost.vecRoute.size() > 0) {
            SDTCroute route = dtchost.vecRoute[0];
            port = route.uPort;
            _MasterAddress = route.szIpadrr;
    }
    ss << ":" << port << "/tcp";
    std::string master_bind_port = ss.str();
    _MasterAddress.append(master_bind_port);
    
    log_info("master address is  [%s]", _MasterAddress.c_str());

    server_.StringKey();
    server_.SetTableName(dtchost.szTablename.c_str());
    server_.SetAddress(_MasterAddress.c_str());
    server_.SetMTimeout(300);

    int ret;
    if ((ret = server_.Ping()) != 0 && ret != -DTC::EC_TABLE_MISMATCH) {
        log_error("ping slave[%s] failed, err: %d", _MasterAddress.c_str(), ret);
        return -1;
    }

    return ret;
}

int HanpinIndex::GetDocByShiftWord(
    FieldInfo fieldInfo,
    std::vector<IndexInfo>& doc_id_set,
    uint32_t appid)
{
    log_debug("GetDocByShiftWord start");
    bool bRet = true;
    std::set<std::vector<Content> > result;
    GetMultipleWords(fieldInfo.word, result);

    int len = result.size();
    if (len <= 0) {
        log_error("get shift word error.");
        return -RT_GET_SUGGEST_ERR;
    }

    std::set<std::vector<Content> >::iterator iter;
    for (iter = result.begin(); iter != result.end(); iter++) 
    {
        IntelligentInfo info;
        std::vector<Content> tmp = *iter;
        ConvertIntelligent(tmp, info, bRet);
        int length = tmp.size();
        if (bRet) {
            bRet = getSuggestDoc(fieldInfo, length, info, doc_id_set, appid);
            if (!bRet) {
                log_error("GetSuggestDocInfo error.");
                return -RT_DTC_ERR;
            }
        }
    }

    return 0;
}

int HanpinIndex::GetDocByShiftEnWord(
    FieldInfo fieldInfo,
    std::vector<IndexInfo>& doc_id_set,
    uint32_t appid)
{
    log_debug("GetDocByShiftEnWord start");
    bool bRet = true;

    int length = 0;
    IntelligentInfo enInfo;
    ConvertCharIntelligent(fieldInfo.word, enInfo, length);
    bRet = getSuggestDocWithoutCharacter(fieldInfo, length, enInfo, doc_id_set, appid);
    if (!bRet) {
        log_error("GetEnSuggestDocInfo error.");
        return -RT_DTC_ERR;
    }
    return 0;
}

bool HanpinIndex::getSuggestDoc(
    uint32_t appid,
    int index, 
    uint32_t len, 
    uint32_t field, 
    const IntelligentInfo& info,
    std::vector<IndexInfo>& doc_id_set)
{
    int ret;
    DTC::Server* dtcServer = &server_;

    if (NULL == dtcServer) {
        log_error("dtcServer is null !");
        return false;
    }

    std::string initial;
    std::stringstream condition;
    std::stringstream ss_key;
    ss_key << appid;
    ss_key << "#";
    ss_key << field;

    DTC::GetRequest getReq(dtcServer);
    ret = getReq.SetKey(ss_key.str().c_str());
    ret = getReq.Need("doc_id");
    ret = getReq.Need("word");
    ret = getReq.Need("doc_version");

    for(int i = 0; i < 8; i++){
        if (info.charact_id[i] != 0) {
            std::stringstream ss_charact;
            ss_charact << "charact_id_0" << i+1;
            condition << ss_charact.str() << info.charact_id[i] << " ";
            ret = getReq.EQ(ss_charact.str().c_str(), info.charact_id[i]);
        }
    }

    for(int i = 0; i < 8; i++){
        if (info.phonetic_id[i] != 0) {
            std::stringstream ss_phonetic;
            ss_phonetic << "phonetic_id_0" << i+1;
            condition << ss_phonetic.str() << info.phonetic_id[i] << " ";
            ret = getReq.EQ(ss_phonetic.str().c_str(), info.phonetic_id[i]);
        }
    }

    for(int i = 0; i < 8; i++){
        if (info.initial_char[i] != "") {
            std::stringstream ss_initial;
            ss_initial << "initial_char_0" << i+1;
            condition << ss_initial.str() << info.initial_char[i] << " ";
            ret = getReq.EQ(ss_initial.str().c_str(), info.initial_char[i].c_str());
        }
    }

    DTC::Result rst;
    ret = getReq.Execute(rst);
    if (ret != 0) {
        if (ret == -110) {
            rst.Reset();
            ret = getReq.Execute(rst);
            if (ret != 0) {
                log_error("get request error! errcode %d,errmsg %s, errfrom %s", ret, rst.ErrorMessage(), rst.ErrorFrom());
                return false;
            }
        }
        else {
            log_error("get request error! errcode %d,errmsg %s, errfrom %s", ret, rst.ErrorMessage(), rst.ErrorFrom());
            return false;
        }
    }

    int cnt = rst.NumRows();
    if (rst.NumRows() <= 0) {
        log_debug("not find in index, key[%s],condition[%s]", ss_key.str().c_str(), condition.str().c_str());
    }
    else {
        for (int i = 0; i < cnt; i++) {
            rst.FetchRow();
            IndexInfo info;
            info.doc_id = rst.StringValue("doc_id");
            info.doc_version = rst.IntValue("doc_version");
            doc_id_set.push_back(info);
            std::string word = rst.StringValue("word");
            if (isAllChinese(word)) {
                ResultContext::Instance()->SetHighLightWordSet(word.substr(index*3, len*3));
            } else {
                ResultContext::Instance()->SetHighLightWordSet(word.substr(index, len));
            }
        }

    }

    return true;
}

bool HanpinIndex::getSuggestDocWithoutCharacter(
    uint32_t appid,
    int index,
    uint32_t len,
    uint32_t field,
    const IntelligentInfo &info,
    std::vector<IndexInfo> &doc_id_set)
{
    int ret;
    DTC::Server* dtcServer = &server_;

    if (NULL == dtcServer) {
        log_error("dtcServer is null !");
        return false;
    }

    std::stringstream ss_key;
    ss_key << appid;
    ss_key << "#";
    ss_key << field;

    std::string initial;
    std::stringstream condition;
    DTC::GetRequest getReq(dtcServer);
    ret = getReq.SetKey(ss_key.str().c_str());
    ret = getReq.Need("doc_id");
    ret = getReq.Need("word");
    ret = getReq.Need("doc_version");

    for(int i = 0; i < 16; i++){
        if (info.initial_char[i] != "") {
            std::stringstream ss_initial;
            if(i + 1 < 10){
                ss_initial << "initial_char_0" << i+1;
            }else {
                ss_initial << "initial_char_" << i+1;
            }
            condition << ss_initial.str() << info.initial_char[i] << " ";
            ret = getReq.EQ(ss_initial.str().c_str(), info.initial_char[i].c_str());
        }
    }

    DTC::Result rst;
    ret = getReq.Execute(rst);
    if (ret != 0) {
        if (ret == -110) {
            rst.Reset();
            ret = getReq.Execute(rst);
            if (ret != 0) {
                log_error("get request error! errcode %d,errmsg %s, errfrom %s", ret, rst.ErrorMessage(), rst.ErrorFrom());
                return false;
            }
        }
        else {
            log_error("get request error! errcode %d,errmsg %s, errfrom %s", ret, rst.ErrorMessage(), rst.ErrorFrom());
            return false;
        }
    }

    int cnt = rst.NumRows();
    if (rst.NumRows() <= 0) {
        log_debug("not find in index, key[%s], condition[%s]", ss_key.str().c_str(), condition.str().c_str());
    }
    else {
        for (int i = 0; i < cnt; i++) {
            rst.FetchRow();
            IndexInfo info;
            info.doc_id = rst.StringValue("doc_id");
            info.doc_version = rst.IntValue("doc_version");
            doc_id_set.push_back(info);
            std::string word = rst.StringValue("word");
            if (isAllChinese(word)) {
                ResultContext::Instance()->SetHighLightWordSet(word.substr(index*3, len*3));
            } else {
                ResultContext::Instance()->SetHighLightWordSet(word.substr(index, len));
            }
        }

    }

    return true;
}

int HanpinIndex::shiftIntelligentInfo(
    IntelligentInfo& info,
    int len)
{
    uint16_t *p = &info.charact_id[0];

    if (len >= 8) {
        return -1;
    }

    if (len < 1) {
        return -2;
    }

    memmove(&p[len], &p[0], sizeof(uint16_t) * (8 - len));

    for (int i = 0; i < len; i++) {
        p[i] = 0;
    }

    p = &info.phonetic_id[0];

    memmove(&p[len], &p[0], sizeof(uint16_t) * (8 - len));

    for (int i = 0; i < len; i++) {
        p[i] = 0;
    }

    GetInitialVec(info, len);

    return 0;
}

bool HanpinIndex::getSuggestDoc(
    FieldInfo& fieldInfo,
    uint32_t len,
    const IntelligentInfo& info,
    std::vector<IndexInfo>& doc_id_set,
    uint32_t appid)
{
    bool bRet;
    int index = 0;
    uint32_t field = fieldInfo.field;
    uint32_t segment_feature = fieldInfo.segment_feature;
    bRet = getSuggestDoc(appid, index, len, field, info, doc_id_set);
    if (bRet == false)
        goto resError;

    if (segment_feature == 0) {
        return true;
    }

    for (uint32_t i = 1; i <= 8 - len; i++) {
        index = index + 1;
        IntelligentInfo t2 = info;
        if (shiftIntelligentInfo(t2, i) < 0) {
            continue;
        }
        bRet = getSuggestDoc(appid, index, len, field, t2, doc_id_set);
        if (bRet == false)
            goto resError;
    }
    return true;

resError:
    log_error("getSuggestDoc invalid.");
    return false;
}

bool HanpinIndex::getSuggestDocWithoutCharacter(
    FieldInfo& fieldInfo,
    uint32_t len,
    const IntelligentInfo& info,
    std::vector<IndexInfo>& doc_id_set,
    uint32_t appid)
{
    bool bRet;
    int index = 0;
    uint32_t field = fieldInfo.field;
    uint32_t segment_feature = fieldInfo.segment_feature;
    bRet = getSuggestDocWithoutCharacter(appid, index, len, field, info, doc_id_set);
    if (bRet == false)
        goto resError;

    if (segment_feature == 0) {
        return true;
    }

    for (uint32_t i = 1; i <= 16 - len; i++) {
        index = index + 1;
        IntelligentInfo t2 = info;
        if (ShiftIntelligentInfoWithoutCharacter(t2, i) < 0) {
            continue;
        }
        bRet = getSuggestDocWithoutCharacter(appid, index, len, field, t2, doc_id_set);
        if (bRet == false)
            goto resError;
    }
    return true;

resError:
    log_error("GetSuggestDoc invalid.");
    return false;
}
